import controller
from messages import *
-class BlkifControllerFactory(controller.ControllerFactory):
- """Factory for creating block device interface controllers.
- Also handles the 'back-end' channel to the device driver domain.
+class BlkifBackendController(controller.BackendController):
+ """ Handler for the 'back-end' channel to a device driver domain.
"""
- def __init__(self):
- controller.ControllerFactory.__init__(self)
+ def __init__(self, factory, dom):
+ controller.BackendController.__init__(self, factory, dom)
self.addMethod(CMSG_BLKIF_BE,
CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED,
self.recv_be_driver_status_changed)
self.attached = 1
self.registerChannel()
+
+ def respond_be_create(self, msg, d):
+ """Response handler for a be_create message.
+ Calls I{d} with the block interface created.
+
+ @param msg: message
+ @type msg: xu message
+ @param d: deferred to call
+ @type d: Deferred
+ """
+ val = unpackMsg('blkif_be_create_t', msg)
+ blkif = self.factory.getInstanceByDom(val['domid'])
+ d.callback(blkif)
+
+ def respond_be_connect(self, msg):
+ """Response handler for a be_connect message.
+
+ @param msg: message
+ @type msg: xu message
+ """
+ val = unpackMsg('blkif_be_connect_t', msg)
+ blkif = self.factory.getInstanceByDom(val['domid'])
+ if blkif:
+ blkif.send_fe_interface_status_changed()
+ else:
+ pass
+
+ def respond_be_vbd_create(self, msg, dev, d):
+ """Response handler for a be_vbd_create message.
+ Tries to grow the vbd, and passes the deferred I{d} on for
+ the grow to call.
+
+ @param msg: message
+ @type msg: xu message
+ @param dev: device
+ @type dev: BlkDev
+ @param d: deferred to call
+ @type d: Deferred
+ """
+ val = unpackMsg('blkif_be_vbd_create_t', msg)
+ blkif = self.factory.getInstanceByDom(val['domid'])
+ if blkif:
+ d1 = defer.Deferred()
+ d1.addCallback(self.respond_be_vbd_grow, dev, d)
+ if d: d1.addErrback(d.errback)
+ blkif.send_be_vbd_grow(val['vdevice'], response=d1)
+ else:
+ pass
+
+ def respond_be_vbd_grow(self, msg, dev, d):
+ """Response handler for a be_vbd_grow message.
+
+ @param msg: message
+ @type msg: xu message
+ @param dev: device
+ @type dev: BlkDev
+ @param d: deferred to call
+ @type d: Deferred or None
+ """
+ val = unpackMsg('blkif_be_vbd_grow_t', msg)
+ status = val['status']
+ if status != BLKIF_BE_STATUS_OKAY:
+ raise XendError("Adding extent to vbd failed: device %x, error %d"
+ % (val['extent.device'], status))
+ if d:
+ d.callback(dev)
+
+ def recv_be_driver_status_changed(self, msg, req):
+ """Request handler for be_driver_status_changed messages.
+
+ @param msg: message
+ @type msg: xu message
+ @param req: request flag (true if the msg is a request)
+ @type req: bool
+ """
+ val = unpackMsg('blkif_be_driver_status_changed_t', msg)
+ status = val['status']
+ if status == BLKIF_DRIVER_STATUS_UP and not self.attached:
+ for blkif in self.factory.getInstances():
+ if blkif.backendController == self:
+ blkif.detach()
+
+
+class BlkifControllerFactory(controller.SplitControllerFactory):
+ """Factory for creating block device interface controllers.
+ """
- def createInstance(self, dom, recreate=0):
+ def __init__(self):
+ controller.SplitControllerFactory.__init__(self)
+ self.attached = 1
+
+ def createInstance(self, dom, recreate=0, backend=0):
"""Create a block device controller for a domain.
@param dom: domain
if blkif:
d.callback(blkif)
else:
- blkif = BlkifController(self, dom)
+ blkif = BlkifController(self, dom, backend)
self.addInstance(blkif)
if recreate:
d.callback(blkif)
else:
d1 = defer.Deferred()
- d1.addCallback(self.respond_be_create, d)
+ d1.addCallback(blkif.backendController.respond_be_create, d)
d1.addErrback(d.errback)
blkif.send_be_create(response=d1)
return d
blkif = self.getInstanceByDom(dom)
return (blkif and blkif.getDevice(vdev)) or None
+ def createBackendController(self, dom):
+ return BlkifBackendController(self, dom)
+
def setControlDomain(self, dom, recreate=0):
"""Set the back-end block device controller domain.
for blkif in self.getInstances():
blkif.reattached()
- def respond_be_create(self, msg, d):
- """Response handler for a be_create message.
- Calls I{d} with the block interface created.
-
- @param msg: message
- @type msg: xu message
- @param d: deferred to call
- @type d: Deferred
- """
- val = unpackMsg('blkif_be_create_t', msg)
- blkif = self.getInstanceByDom(val['domid'])
- d.callback(blkif)
-
- def respond_be_connect(self, msg):
- """Response handler for a be_connect message.
- @param msg: message
- @type msg: xu message
- """
- val = unpackMsg('blkif_be_connect_t', msg)
- blkif = self.getInstanceByDom(val['domid'])
- if blkif:
- blkif.send_fe_interface_status_changed()
- else:
- pass
-
- def respond_be_vbd_create(self, msg, dev, d):
- """Response handler for a be_vbd_create message.
- Tries to grow the vbd, and passes the deferred I{d} on for
- the grow to call.
-
- @param msg: message
- @type msg: xu message
- @param dev: device
- @type dev: BlkDev
- @param d: deferred to call
- @type d: Deferred
- """
- val = unpackMsg('blkif_be_vbd_create_t', msg)
- blkif = self.getInstanceByDom(val['domid'])
- if blkif:
- d1 = defer.Deferred()
- d1.addCallback(self.respond_be_vbd_grow, dev, d)
- if d: d1.addErrback(d.errback)
- blkif.send_be_vbd_grow(val['vdevice'], response=d1)
- else:
- pass
-
- def respond_be_vbd_grow(self, msg, dev, d):
- """Response handler for a be_vbd_grow message.
-
- @param msg: message
- @type msg: xu message
- @param dev: device
- @type dev: BlkDev
- @param d: deferred to call
- @type d: Deferred or None
- """
- val = unpackMsg('blkif_be_vbd_grow_t', msg)
- status = val['status']
- if status != BLKIF_BE_STATUS_OKAY:
- raise XendError("Adding extent to vbd failed: device %x, error %d"
- % (val['extent.device'], status))
- if self.attached:
- if d:
- d.callback(dev)
- else:
- self.reattachDevice(val['domid'], val['vdevice'])
-
- def recv_be_driver_status_changed(self, msg, req):
- """Request handler for be_driver_status_changed messages.
-
- @param msg: message
- @type msg: xu message
- @param req: request flag (true if the msg is a request)
- @type req: bool
- """
- val = unpackMsg('blkif_be_driver_status_changed_t', msg)
- status = val['status']
- if status == BLKIF_DRIVER_STATUS_UP and not self.attached:
- for blkif in self.getInstances():
- blkif.detach()
class BlkDev(controller.Dev):
"""Info record for a block device.
log.debug("Destroying vbd domain=%d vdev=%d", self.controller.dom, self.vdev)
self.controller.send_be_vbd_destroy(self.vdev)
-class BlkifController(controller.Controller):
+class BlkifController(controller.SplitController):
"""Block device interface controller. Handles all block devices
for a domain.
"""
- def __init__(self, factory, dom):
- controller.Controller.__init__(self, factory, dom)
+ def __init__(self, factory, dom, backend):
+ controller.SplitController.__init__(self, factory, dom, backend)
self.devices = {}
self.addMethod(CMSG_BLKIF_FE,
CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED,
d.callback(dev)
else:
d1 = defer.Deferred()
- d1.addCallback(self.factory.respond_be_vbd_create, dev, d)
+ d1.addCallback(self.backendController.respond_be_vbd_create, dev, d)
d1.addErrback(d.errback)
self.send_be_vbd_create(vdev, response=d1)
return d
for dev in self.devices.values():
dev.attached = 0
d1 = defer.Deferred()
- d1.addCallback(self.factory.respond_be_vbd_create, None, None)
+ d1.addCallback(self.backendController.respond_be_vbd_create, None, None)
self.send_be_vbd_create(vdev, response=d1)
def reattachDevice(self, vdev):
'evtchn' : self.evtchn['port1'],
'shmem_frame' : val['shmem_frame'] })
d = defer.Deferred()
- d.addCallback(self.factory.respond_be_connect)
- self.factory.writeRequest(msg, response=d)
+ d.addCallback(self.backendController.respond_be_connect)
+ self.backendController.writeRequest(msg, response=d)
def send_fe_interface_status_changed(self, response=None):
msg = packMsg('blkif_fe_interface_status_changed_t',
msg = packMsg('blkif_be_create_t',
{ 'domid' : self.dom,
'blkif_handle' : 0 })
- self.factory.writeRequest(msg, response=response)
+ self.backendController.writeRequest(msg, response=response)
def send_be_disconnect(self, response=None):
log.debug('>BlkifController>send_be_disconnect> dom=%d', self.dom)
msg = packMsg('blkif_be_disconnect_t',
{ 'domid' : self.dom,
'blkif_handle' : 0 })
- self.factory.writeRequest(msg, response=response)
+ self.backendController.writeRequest(msg, response=response)
def send_be_destroy(self, response=None):
log.debug('>BlkifController>send_be_destroy> dom=%d', self.dom)
msg = packMsg('blkif_be_destroy_t',
{ 'domid' : self.dom,
'blkif_handle' : 0 })
- self.factory.writeRequest(msg, response=response)
+ self.backendController.writeRequest(msg, response=response)
def send_be_vbd_create(self, vdev, response=None):
dev = self.devices[vdev]
'blkif_handle' : 0,
'vdevice' : dev.vdev,
'readonly' : dev.readonly() })
- self.factory.writeRequest(msg, response=response)
+ self.backendController.writeRequest(msg, response=response)
def send_be_vbd_grow(self, vdev, response=None):
dev = self.devices[vdev]
'extent.device' : dev.device,
'extent.sector_start' : dev.start_sector,
'extent.sector_length' : dev.nr_sectors })
- self.factory.writeRequest(msg, response=response)
+ self.backendController.writeRequest(msg, response=response)
def send_be_vbd_destroy(self, vdev, response=None):
log.debug('>BlkifController>send_be_vbd_destroy> dom=%d vdev=%d', self.dom, vdev)
'blkif_handle' : 0,
'vdevice' : dev.vdev })
del self.devices[vdev]
- self.factory.writeRequest(msg, response=response)
+ self.backendController.writeRequest(msg, response=response)
else:
print 'CtrlMsgRcvr>writeResponse>', 'no channel!', self
-class ControllerFactory(CtrlMsgRcvr):
+class ControllerFactory:
"""Abstract class for factories creating controllers for a domain.
Maintains a table of instances.
"""
def __init__(self):
- CtrlMsgRcvr.__init__(self)
self.instances = {}
+ self.backends = {}
self.dom = 0
def addInstance(self, instance):
self.deregisterChannel()
self.factory.instanceClosed(self)
+class SplitControllerFactory(ControllerFactory):
+ """Factory for SplitControllers.
+
+ @ivar backends: mapping of domain id to backend
+ @type backends: {int: BackendController}
+ """
+
+ def __init__(self):
+ ControllerFactory.__init__(self)
+ self.backends = {}
+
+ def createInstance(self, dom, recreate=0, backend=0):
+ """Create an instance. Define in a subclass.
+
+ @param dom: domain
+ @type dom: int
+ @param recreate: true if the instance is being recreated (after xend restart)
+ @type recreate: int
+ @param backend: backend domain
+ @type backend: int
+ @return: controller instance
+ @rtype: SplitController (or subclass)
+ """
+ raise NotImplementedError()
+
+ def getBackendController(self, dom):
+ """Get the backend controller for a domain.
+
+ @param dom: domain
+ @return: backend controller
+ """
+ ctrlr = self.backends.get(dom)
+ if ctrlr is None:
+ ctrlr = self.createBackendController(dom)
+ self.backends[dom] = ctrlr
+ return ctrlr
+
+ def createBackendController(self, dom):
+ """Create a backend controller. Define in a subclass.
+
+ @param dom: domain
+ """
+ raise NotImplementedError()
+
+ def delBackendController(self, ctrlr):
+ """Remove a backend controller.
+
+ @param ctrlr: backend controller
+ """
+ if ctrlr.dom in self.backends:
+ del self.backends[ctrlr.dom]
+
+ def backendControllerClosed(self, ctrlr):
+ """Callback called when a backend is closed.
+ """
+ self.delBackendController(ctrlr)
+
+class BackendController(CtrlMsgRcvr):
+ """Abstract class for a backend device controller attached to a domain.
+
+ @ivar factory: controller factory
+ @type factory: ControllerFactory
+ @ivar dom: domain
+ @type dom: int
+ @ivar channel: channel to the domain
+ @type channel: Channel
+ """
+
+
+ def __init__(self, factory, dom):
+ CtrlMsgRcvr.__init__(self)
+ self.factory = factory
+ self.dom = int(dom)
+ self.channel = None
+
+ def close(self):
+ self.lostChannel()
+
+ def lostChannel(self):
+ self.deregisterChannel()
+ self.factory.instanceClosed(self)
+
+
+class SplitController(Controller):
+ """Abstract class for a device controller attached to a domain.
+ A SplitController has a BackendContoller.
+ """
+
+ def __init__(self, factory, dom, backend):
+ Controller.__init__(self, factory, dom)
+ self.backendDomain = None
+ self.backendController = None
+ self.setBackendDomain(backend)
+
+ def setBackendDomain(self, dom):
+ ctrlr = self.factory.getBackendController(dom)
+ self.backendDomain = ctrlr.dom
+ self.backendController = ctrlr
+
+ def getBackendDomain(self):
+ return self.backendDomain
+
+ def getBackendController(self):
+ return self.backendController
+
class Dev:
"""Abstract class for a device attached to a device controller.
import controller
from messages import *
-class NetifControllerFactory(controller.ControllerFactory):
- """Factory for creating network interface controllers.
- Also handles the 'back-end' channel to the device driver domain.
+class NetifBackendController(controller.BackendController):
+ """Handler for the 'back-end' channel to a device driver domain.
"""
-
- def __init__(self):
- controller.ControllerFactory.__init__(self)
+
+ def __init__(self, factory, dom):
+ controller.BackendController.__init__(self, factory, dom)
self.addMethod(CMSG_NETIF_BE,
CMSG_NETIF_BE_DRIVER_STATUS_CHANGED,
self.recv_be_driver_status_changed)
self.attached = 1
self.registerChannel()
- def createInstance(self, dom, recreate=0):
+ def respond_be_connect(self, msg):
+ val = unpackMsg('netif_be_connect_t', msg)
+ dom = val['domid']
+ vif = val['netif_handle']
+ netif = self.factory.getInstanceByDom(dom)
+ if netif:
+ netif.send_interface_connected(vif)
+ else:
+ log.warning("respond_be_connect> unknown vif dom=%d vif=%d", dom, vif)
+ pass
+
+ def recv_be_driver_status_changed(self, msg, req):
+ val = unpackMsg('netif_be_driver_status_changed_t', msg)
+ status = val['status']
+ if status == NETIF_DRIVER_STATUS_UP and not self.attached:
+ # If we are not attached the driver domain was changed, and
+ # this signals the new driver domain is ready.
+ for netif in self.factory.getInstances():
+ if netif.backendController == self:
+ netif.reattach_devices()
+ self.attached = 1
+
+class NetifControllerFactory(controller.SplitControllerFactory):
+ """Factory for creating network interface controllers.
+ """
+
+ def __init__(self):
+ controller.ControllerFactory.__init__(self)
+ self.attached = 1
+
+ def createInstance(self, dom, recreate=0, backend=0):
"""Create or find the network interface controller for a domain.
@param dom: domain
"""
netif = self.getInstanceByDom(dom)
if netif is None:
- netif = NetifController(self, dom)
+ netif = NetifController(self, dom, backend=backend)
self.addInstance(netif)
return netif
netif = self.getInstanceByDom(dom)
return (netif and netif.getDevice(vif)) or None
+ def createBackendController(self, dom):
+ return NetifBackendController(self, dom)
+
def setControlDomain(self, dom, recreate=0):
"""Set the 'back-end' device driver domain.
"""
return self.dom
- def respond_be_connect(self, msg):
- val = unpackMsg('netif_be_connect_t', msg)
- dom = val['domid']
- vif = val['netif_handle']
- netif = self.getInstanceByDom(dom)
- if netif:
- netif.send_interface_connected(vif)
- else:
- log.warning("respond_be_connect> unknown vif dom=%d vif=%d", dom, vif)
- pass
-
- def recv_be_driver_status_changed(self, msg, req):
- val = unpackMsg('netif_be_driver_status_changed_t', msg)
- status = val['status']
- if status == NETIF_DRIVER_STATUS_UP and not self.attached:
- # If we are not attached the driver domain was changed, and
- # this signals the new driver domain is ready.
- for netif in self.getInstances():
- netif.reattach_devices()
- self.attached = 1
-
class NetDev(controller.Dev):
"""Info record for a network device.
"""
self.controller.send_be_disconnect(self.vif, response=d)
-class NetifController(controller.Controller):
+class NetifController(controller.SplitController):
"""Network interface controller. Handles all network devices for a domain.
"""
- def __init__(self, factory, dom):
- controller.Controller.__init__(self, factory, dom)
+ def __init__(self, factory, dom, backend):
+ controller.SplitController.__init__(self, factory, dom, backend)
self.devices = {}
-
self.addMethod(CMSG_NETIF_FE,
CMSG_NETIF_FE_DRIVER_STATUS_CHANGED,
self.recv_fe_driver_status_changed)
'tx_shmem_frame' : val['tx_shmem_frame'],
'rx_shmem_frame' : val['rx_shmem_frame'] })
d = defer.Deferred()
- d.addCallback(self.factory.respond_be_connect)
- self.factory.writeRequest(msg, response=d)
+ d.addCallback(self.backendController.respond_be_connect)
+ self.backendController.writeRequest(msg, response=d)
def send_interface_connected(self, vif, response=None):
dev = self.devices[vif]
{ 'domid' : self.dom,
'netif_handle' : dev.vif,
'mac' : dev.mac })
- self.factory.writeRequest(msg, response=response)
+ self.backendController.writeRequest(msg, response=response)
def send_be_disconnect(self, vif, response=None):
dev = self.devices[vif]
msg = packMsg('netif_be_disconnect_t',
{ 'domid' : self.dom,
'netif_handle' : dev.vif })
- self.factory.writeRequest(msg, response=response)
+ self.backendController.writeRequest(msg, response=response)
def send_be_destroy(self, vif, response=None):
dev = self.devices[vif]
msg = packMsg('netif_be_destroy_t',
{ 'domid' : self.dom,
'netif_handle' : vif })
- self.factory.writeRequest(msg, response=response)
+ self.backendController.writeRequest(msg, response=response)